#include "bsp_i2c.h"
#include "i2c_port.h"


static i2cPortOps_t i2cStruct = {
    i2cGpioInit,
    i2cSetSdaStatus,
    i2cSetSclStatus,
    i2cSdaModeSwitch,
    i2cGetSdaStatus,
    i2cDelay,
};
static i2cPortOps_t *i2cOps = NULL;

/**
 * @brief i2c Send Start Signal
 * 
 */
void i2cStart(void){
    if(i2cOps->i2cModeSwitch){
        i2cOps->i2cModeSwitch(1);
    }
    i2cOps->i2cSetSda(1);
    i2cOps->i2cSetScl(1);
    i2cOps->i2cDelay(4);
    i2cOps->i2cSetSda(0);
    i2cOps->i2cDelay(4);
    i2cOps->i2cSetScl(0);
}

/**
 * @brief i2c Send Stop Signal
 * 
 */
void i2cStop(void){
    if(i2cOps->i2cModeSwitch){
        i2cOps->i2cModeSwitch(1);
    }
    i2cOps->i2cSetScl(0);
    i2cOps->i2cSetSda(0);
    i2cOps->i2cDelay(4);
    i2cOps->i2cSetScl(1);
    i2cOps->i2cSetSda(1);
    i2cOps->i2cDelay(4);
}

/**
 * @brief i2c wait slave response
 * 
 * @return uint8_t 
 */
uint8_t i2cWaitAck(void){
    uint8_t ucErrTime = 0;
	if(i2cOps->i2cModeSwitch){
        i2cOps->i2cModeSwitch(0);
    }      
	i2cOps->i2cSetSda(1);
	i2cOps->i2cDelay(1);
	i2cOps->i2cSetScl(1);
	i2cOps->i2cDelay(1);
	while(i2cOps->i2cGetSda()){
		ucErrTime++;
		if(ucErrTime > 250){
			i2cStop();
			return 1;
		}
	}
	i2cOps->i2cSetScl(0);  
	return 0;
}

/**
 * @brief i2c master send response  to slave
 * 
 */
void i2cAck(void){
    i2cOps->i2cSetScl(0);
	if(i2cOps->i2cModeSwitch){
        i2cOps->i2cModeSwitch(1);
    }
	i2cOps->i2cSetSda(0);
	i2cOps->i2cDelay(2);
	i2cOps->i2cSetScl(1); 
	i2cOps->i2cDelay(2);
	i2cOps->i2cSetScl(0); 
}

/**
 * @brief i2c send no ack to slave
 * 
 */
void i2cNoAck(void){
	i2cOps->i2cSetScl(0);
	if(i2cOps->i2cModeSwitch){
        i2cOps->i2cModeSwitch(1);
    }
	i2cOps->i2cSetSda(1);
	i2cOps->i2cDelay(2);
	i2cOps->i2cSetScl(1); 
	i2cOps->i2cDelay(2);
	i2cOps->i2cSetScl(0); 
}

/**
 * @brief i2c send date to slave
 * 
 * @param date 
 */
void i2cWriteByte(uint8_t date){
    uint8_t t;
	if(i2cOps->i2cModeSwitch){
        i2cOps->i2cModeSwitch(1);
    }
	i2cOps->i2cSetScl(0); 
	for(t = 0; t < 8; t++){
        if((date & 0x80) >> 7){
            i2cOps->i2cSetSda(1);
        }else{
            i2cOps->i2cSetSda(0);
        }
		date <<= 1;
		i2cOps->i2cDelay(2);   
		i2cOps->i2cSetScl(1);
		i2cOps->i2cDelay(2);
		i2cOps->i2cSetScl(0);
		i2cOps->i2cDelay(2);
	}
}

/**
 * @brief i2c read one byte
 * 
 * @param ack is need response
 * @return uint8_t 
 */
uint8_t i2cReadByte(uint8_t ack){
    uint8_t i, receive = 0;
	if(i2cOps->i2cModeSwitch){
        i2cOps->i2cModeSwitch(0);
    } 
	for(i = 0; i < 8; i++){
		i2cOps->i2cSetScl(0);
		i2cOps->i2cDelay(2);
		i2cOps->i2cSetScl(1);
		receive <<= 1;
		if(i2cOps->i2cGetSda()){
            receive++;
        }
		i2cOps->i2cDelay(1);
	}
	if(!ack){
        i2cNoAck();
    }else{
        i2cAck(); 
    }
	return receive;
}

/**
 * @brief i2c protocol init
 * 
 */
void i2cInit(void){
    i2cOps = &i2cStruct;
    i2cOps->i2cPortInit();
    i2cOps->i2cSetScl(1);
    i2cOps->i2cSetSda(1);
}
